/**
 * Copyright 2009 Adam Ruggles.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing categoryPermissionsMap and
 * limitations under the License.
 */
package com.google.code.sapien.security;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.code.sapien.model.Category;
import com.google.code.sapien.model.CategoryAcl;
import com.google.code.sapien.model.User;

/**
 * A default implementation of {@link com.google.code.sapien.security.SecurityDetails}.
 * @author Adam
 * @version $Id: SapienSecurityDetails.java 30 2010-01-10 19:05:55Z a.ruggles $
 * 
 * Created on Mar 4, 2009 at 9:31:16 PM 
 */
public class SapienSecurityDetails implements SecurityDetails, Serializable {
	/**
	 * Serial Version UID.
	 */
	private static final long serialVersionUID = -242291291433869388L;

	/**
	 * A list of category Access Control List entries.
	 */
	private final List<CategoryAcl> acls = new ArrayList<CategoryAcl>();

	/**
	 * A flag to store the administrator status.
	 */
	private boolean administrator;

	/**
	 * A flag to determine if the user is anonymous.
	 */
	private final boolean anonymous;

	/**
	 * A map of categoryPermissionsMap by the forum id.
	 */
	private final Map<Long, CategoryPermissions> categoryPermissionsMap = new HashMap<Long, CategoryPermissions>();

	/**
	 * The IP Address of the remote user.
	 */
	private String ipAddress;

	/**
	 * The user that is current online.
	 */
	private final User user;

	/**
	 * Constructs an anonymous Sapien online user.
	 * @param acls The category ACL Entries.
	 */
	public SapienSecurityDetails(final Collection<CategoryAcl> acls) {
		this.user = null;
		anonymous = true;
		setPermissions(acls);
	}

	/**
	 * Constructs a Sapien online user.
	 * @param user The user that is currently online.
	 * @param acls The category ACL Entries.
	 */
	public SapienSecurityDetails(final User user, final Collection<CategoryAcl> acls) {
		this.user = user;
		anonymous = false;
		setPermissions(acls);
	}

	/**
	 * {@inheritDoc}
	 * @see com.google.code.sapien.security.SecurityDetails#checkCategory(com.google.code.sapien.model.Category,
	 * com.google.code.sapien.security.CategoryPermissions)
	 */
	public boolean checkCategory(final Category category, final CategoryPermissions permissions) {
		CategoryPermissions categoryPermissions = categoryPermissionsMap.get(category.getId());
		if (categoryPermissions == null) {
			return false;
		}
		return categoryPermissions.check(permissions);
	}

	/**
	 * {@inheritDoc}
	 * @see com.google.code.sapien.security.SecurityDetails#getIpAddress()
	 */
	public String getIpAddress() {
		return ipAddress;
	}

	/**
	 * {@inheritDoc}
	 * @see com.google.code.sapien.security.SecurityDetails#getUser()
	 */
	public User getUser() {
		return user;
	}

	/**
	 * {@inheritDoc}
	 * @see com.google.code.sapien.security.SecurityDetails#isAdministrator()
	 */
	public boolean isAdministrator() {
		return administrator;
	}

	/**
	 * {@inheritDoc}
	 * @see com.google.code.sapien.security.SecurityDetails#isAnonymous()
	 */
	public boolean isAnonymous() {
		return anonymous;
	}

	/**
	 * {@inheritDoc}
	 * @see com.google.code.sapien.security.SecurityDetails#setIpAddress(java.lang.String)
	 */
	public void setIpAddress(final String ipAddress) {
		this.ipAddress = ipAddress;
	}

	/**
	 * Collects all the permissions for the security details objects and sets them to their internal representation.
	 * @param acls A collection of access control list entries.
	 */
	private void setPermissions(final Collection<CategoryAcl> acls) {
		administrator = false;
		for (CategoryAcl acl : acls) {
			this.acls.add(acl);
			if (Boolean.TRUE.equals(acl.getRole().getAdministrator())) {
				administrator = true;
			}
			// Get the category permissions.
			CategoryPermissions categoryPermissions = categoryPermissionsMap.get(acl.getCategory().getId());
			if (categoryPermissions == null) {
				// Set the new category permissions to the map.
				categoryPermissionsMap.put(acl.getCategory().getId(), acl.getPermissions());
			} else {
				// Add the additional category permissions to the entry.
				categoryPermissions.add(acl.getPermissions());
			}
		}
	}
}
